using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;

namespace Woz
{
    /// <summary>
    /// clone entity action clones entities on the screen
    /// </summary>
    internal class CloneAction : Woz.Action
    {
        /// <summary>
        /// creates an instance of the clone action
        /// </summary>
        /// <param name="pEntities">the entities to clone on the screen</param>
        public CloneAction(params Woz.Entity[] pEntities)
        {
            // save the entities to remove
            this.mEntities = pEntities;

            // initialize the clones
            this.mClones = new Woz.Entity[pEntities.Length];

            // compute the bounding box of the entities to remove
            this.mBoundingRect = Woz.Entity.ComputeBoundingBox(this.mEntities);

            // inflate the bounding box by ten pixels
            this.mBoundingRect.Inflate(Woz.InkSpaceConverter.Instance.InkSpaceTenPixels,
                Woz.InkSpaceConverter.Instance.InkSpaceTenPixels);

            // inflate the bounding box by two more pixels
            this.mBoundingRect.Inflate(Woz.InkSpaceConverter.Instance.InkSpaceTwoPixels,
                Woz.InkSpaceConverter.Instance.InkSpaceTwoPixels);

            // inflate the bounding box by ten more pixels
            this.mBoundingRect.Inflate(Woz.InkSpaceConverter.Instance.InkSpaceTenPixels,
                Woz.InkSpaceConverter.Instance.InkSpaceTenPixels);

            // make action string
            if (this.mEntities.Length == 1)
            {
                this.mActionString = String.Concat("Cloned ", this.mEntities[0].ToString());
            }
            else
            {
                this.mActionString = String.Format("Cloned {0} Entities", this.mEntities.Length);
            }
        }

        /// <summary>
        /// gets the name of the tool this action prefers
        /// </summary>
        public override string ToolName
        {
            get
            {
                return "Select";
            }
        }

        /// <summary>
        /// gets whether this action can be propagated or not
        /// </summary>
        public override bool Propagatable
        {
            get
            {
                return false;
            }
        }

        /// <summary>
        /// removes the entities from the screen
        /// </summary>
        /// <param name="pScreen">not used for non propagateable action</param>
        protected override void OnExecute(Woz.Screen pScreen)
        {
            // save the paste offset so we dont have to look it up in the loop
            int pasteOffset = Woz.StaticVariables.Instance.PasteOffset * 
                Woz.DynamicVariables.Instance.ConsecutivePaste;

            // remove each of the entities from the screen
            for (int i = this.mEntities.Length - 1; i >= 0; i--)
            {
                // clone it
                this.mClones[i] = this.mEntities[i].Clone() as Woz.Entity;

                // deselect the old one
                this.mScreen.DeselectEntity(this.mEntities[i], false);
                
                // move the clone by twenty pixels
                this.mClones[i].Translate(pasteOffset, pasteOffset);

                // add the clone
                this.mScreen.AddEntity(this.mClones[i], false);

                // select the clone
                this.mScreen.SelectEntity(this.mClones[i], false);
            }

            // now request the screen to update the bounding box
            Woz.ScreenManager.Instance.RequestSelectedScreenUpdate(pScreen, this.mBoundingRect);

            // also request the thumbnail to update
            Woz.ScreenManager.Instance.RequestSelectedScreenThumbnailUpdate(pScreen);
        }

        /// <summary>
        /// adds the entitis back to the screen
        /// </summary>
        /// <param name="pScreen">not used for non propagateable action</param>
        protected override void OnUnExecute(Woz.Screen pScreen)
        {
            // remove each of the entities from the screen
            for (int i = this.mEntities.Length - 1; i >= 0; i--)
            {
                // deselect the clone
                this.mScreen.DeselectEntity(this.mClones[i], false);

                // remove the clone from the screen
                this.mScreen.RemoveEntity(this.mClones[i], false);

                // dispose of the clone
                this.mClones[i].Dispose();
                this.mClones[i] = null;

                // select the original
                this.mScreen.SelectEntity(this.mEntities[i], false);
            }

            // now request the screen to update the bounding box
            Woz.ScreenManager.Instance.RequestSelectedScreenUpdate(pScreen, this.mBoundingRect);

            // also request the thumbnail to update
            Woz.ScreenManager.Instance.RequestSelectedScreenThumbnailUpdate(pScreen);
        }

        /// <summary>
        /// the entities to clone
        /// </summary>
        private Woz.Entity[] mEntities;

        /// <summary>
        /// the produced clones
        /// </summary>
        private Woz.Entity[] mClones;

        /// <summary>
        /// the bounding box of the entities to remove
        /// </summary>
        private Rectangle mBoundingRect;
    }
}
